// textfile.h: interface for the textfile class.
//
//////////////////////////////////////////////////////////////////////

#ifndef PEKSPRODUCTIONS_TEXTFILE
#define PEKSPRODUCTIONS_TEXTFILE



/*
	CTextFileDocument let you write and read text files with 
	different encodings (ASCII, UTF-8, Unicode 16 little/big 
	endian is supported). When you work with ASCII-files
	CTextFileDocument will help you convert strings to/from
	different code-pages.

	Let me now if you find something strange or just gets
	a clever idea...

	Get the latest version at 
	http://www.codeproject.com/file/textfiledocument.asp

	Version 1.22 - 21 May 2005
	 ! Reading a line before reading everything could add an
	   extra line break.
	 ! A member variable wasn't always initialized, could cause
	   problems when reading single lines.
	 ! A smarter/easier algorithm is used when reading single lines.

	Version 1.21 - 10 Apr 2005
	 ! Fix by sammyc: If it was not possible to open a file in techlevel 1,
	   IsOpen returned a bad result.

	Version 1.20 - 15 Jan 2005
	 ! Fixed some problems when converting multi-byte string to Unicode,
	   and vice versa.
	 + Improved conversion routines. It's now possible to define
	   which code-page to use.
	 + It's now possible to set which character to use when it's
	   not possible to convert an Unicode character to an multi-byte character.
	 + It's now possible to see if data was lost during conversion.
	 + Better support for other platforms, it's no longer necessary to use
	   MFC in Windows.
	 ! Reading very small files (1 byte) failed.

	Version 1.13 - 26 Dec 2004
	 ! Fixes by drinktea:
	 ! If a text file begun with an empty line, the file
	   wasn't read correctly (first empty line was ignored).
	 ! Fixes in CharToWstring and WcharToString.

	Version 1.12 - 17 Oct 2004
	 + Minor memory leak when open file failed, fixed.

	Version 1.11 - 28 Aug 2004
	 ! Calling WriteEndl() when writing an ASCII file could make
	   the file incorrectly written. Fixed.
	 + ASCII files is written faster.

	Version 1.10 - 13 Aug 2004
	Sorry about the quick update.
	 + Improved performance (much faster now, but code is more complicated :-/).
	 + Buffer is used when writing files.
	 + Buffer is used in non-mfc compilers

	Version 1.0	- 12 Aug 2004
	Initial version.

	PEK
  */


/*

If you are creating a console project that doesn't support
MFC in Visual Studio, you will probably need to define
techlevel to 0:
#define PEK_TX_TECHLEVEL 0

In other cases it usually not necessary to define which "tech-level" 
to use, the code below should do this for you. However, 
if you need to this is the difference:

#define PEK_TX_TECHLEVEL 0
You should use this if you running on a none-Windows 
platform. This uses fstream internally to read and 
write files. If you want to change codepage you should 
call setlocal.

#define PEK_TX_TECHLEVEL 1
Use this on Windows if you don't use MFC. This calls 
Windows API directly to read and write files. If 
something couldn't be read/written a CTextFileException 
is thrown. Unicode in filenames are supported. 
Codepages are supported.

#define PEK_TX_TECHLEVEL 2
Use this when you are using MFC. This uses CFile 
internally to read and write files. If data can't be 
read/written, CFile will throw an exception. Codepages 
are supported. Unicode in filenames are supported.
CString is supported.

*/


	/*
		In windows it's possible to use Unicode in filenames,
		in unix it's not possible (afaik). FILENAMECHAR is the 
		charactertype.
	  */
	//#include <afx.h>

	#ifndef _UNICODE
		typedef char FILENAMECHAR;
	#else
		typedef wchar_t FILENAMECHAR;
	#endif

//#include <string>

//using namespace std;


//This is only used in Windows mode (no MFC)
//An exception is thrown will data couldn't be read or written
// class CTextFileException
// {
// public:
// 	CTextFileException(DWORD err)
// 	{
// 		m_errorCode = err;
// 	}
// 
// 	//Value returned by GetLastError()
// 	DWORD m_errorCode;
// };

class CTextFileBase
{
public:
	enum TEXTENCODING { ASCII, UNI16_BE, UNI16_LE, UTF_8 };

	//Base constructor
	CTextFileBase()
	{
		m_codepage = CP_ACP;
		m_unknownChar = 0;

		m_hFile = INVALID_HANDLE_VALUE;

		m_datalost = false;

		m_buffpos = -1;
	}

	//Base destructor
	~CTextFileBase()
	{
		Close();
	}


	//Is file open?
	int IsOpen() 
	{
		return m_hFile != INVALID_HANDLE_VALUE;
	}

    LONGLONG Size() 
    {
        LARGE_INTEGER size = {0,0};
        if (GetFileSizeEx(m_hFile, &size) == 0) {
            return 0;
        }
        return size.QuadPart;
    }
	
	//Close the file
	void Close()
	{
		if(IsOpen())
		{
			::CloseHandle(m_hFile);
			m_hFile = INVALID_HANDLE_VALUE;
		}

	}

	//Return the encoding of the file (ASCII, UNI16_BE, UNI16_LE or UTF_8);
	TEXTENCODING GetEncoding() const 
	{
		return m_encoding;
	};


	//Set which character that should be used when converting
	//Unicode->multi byte and an unknown character is found ('?' is default)
	void SetUnknownChar(const char unknown)
	{
		m_unknownChar = unknown;
	}


	//Returns true if data was lost
	//(happens when converting Unicode->multi byte string and an unmappable
	//characters is found).
	bool IsDataLost() const
	{
		return m_datalost;
	}

	//Reset the data lost flag
	void ResetDataLostFlag()
	{
		m_datalost = false;
	}

	/* Note!
	   The codepage is only used when converting from multibyte
	   to Unicode or vice versa. It is not used when reading
	   ANSI-files in none-Unicode strings, or reading
	   Unicode-files in Unicode strings.

	   This means that if you want to read a ANSI-textfile
	   (with some code page) to an non-Unicode string you
	   must do the conversion yourself. But this is easy :-).
	   Read the file with the codepage to a CStringW, then use
	   ConvertCharToWstring to convert the CStringW to a
	   string.

	*/
	
	//Make sure we have a legal value for code page to use when
	//converting string. Used for debugging only.
#define IsLegalCodePage(cp) (cp == CP_ACP || cp == CP_MACCP || cp == CP_OEMCP || cp == CP_SYMBOL || cp == CP_THREAD_ACP || cp == CP_UTF7 || cp == CP_UTF8 || IsValidCodePage(cp))

#ifndef ASSERT 
	#define ASSERT ATLASSERT
#endif

	//(Windows-specific) Set codepage to use when working with non-unicode strings.
	void SetCodePage(const UINT codepage)
	{
		ASSERT(IsLegalCodePage(codepage));
		m_codepage = codepage;
	}


	//(Windows-specific) Get codepage to use when working with non-unicode strings.
	UINT GetCodePage() const
	{
		return m_codepage;
	}

	//(Windows-specific) Convert char* to CStringW
	void ConvertCharToWstring(const char* from, CStringW &to, UINT codepage)
	{
		to = L"";

		ASSERT(IsLegalCodePage(codepage));
		//Use api convert routine
		int wlen = MultiByteToWideChar( codepage,
			0,
			from,
			-1,
			NULL,
			0);

		//if wlen == 0, some unknown codepage was probably used.
		ASSERT(wlen);
		if(wlen == 0) 
			return;

		//wchar_t* wbuffer = new wchar_t[wlen+2];
		wchar_t* wbuffer = to.GetBufferSetLength(wlen+2);

		MultiByteToWideChar(    codepage,
			0,
			from,
			-1,
			wbuffer,
			wlen);

		//to = wbuffer;
		//delete [] wbuffer;
		to.ReleaseBuffer();

	}

	//(Windows-specific) Convert wchar_* to string
	void ConvertWcharToString(const wchar_t* from, CStringA &to, 
		UINT codepage, bool* datalost, char unknownchar)
	{
		to = "";

		ASSERT(IsLegalCodePage(codepage));

		int alen = 	WideCharToMultiByte(	codepage,
			0,
			from,
			-1, 
			NULL,
			0,
			NULL,
			NULL);

		//if alen == 0, some unknown codepage was probably used.
		ASSERT(alen);
		if(alen == 0) 
			return;


		//Use mfc convert routine
		//char* abuffer = new char[alen+2]; 
		char* abuffer = to.GetBufferSetLength(alen + 1); 
		BOOL UsedDefault=FALSE;

		WideCharToMultiByte(	codepage,
			0,
			from,
			-1,
			abuffer,
			alen, 
			(unknownchar != 0 ? &unknownchar : NULL),
			(datalost != NULL ? &UsedDefault : NULL)
			);


		if( datalost != NULL && UsedDefault != FALSE)
			*datalost = true;

		//to = abuffer;
		//delete [] abuffer;
		to.ReleaseBuffer();
	}

protected:
	//(Windows-specific) Convert string to CStringW with current codepage
	inline void CharToWstring(const char* from, CStringW &to)
	{
		ConvertCharToWstring(from, to, m_codepage);
	}

	//(Windows-specific) Convert CStringW to string with current codepage
	inline void WcharToString(const wchar_t* from, CStringA &to) 
	{
		ConvertWcharToString(from, to, m_codepage, &m_datalost, m_unknownChar);
	}

protected:
		
	//The enocoding of the file
	TEXTENCODING m_encoding;

	//Buffersize
	#define BUFFSIZE 1024


	HANDLE m_hFile;
	
	//These controls the buffer for reading/writing

	//True if end of file
	bool m_endoffile;
	//Readingbuffer
	char m_buf[BUFFSIZE];
	//Bufferposition
	int m_buffpos;
	//Size of buffer
	int m_buffsize;

	//Character used when converting Unicode->multi byte and an unknown character was found
	char m_unknownChar;

	//Is true if data was lost when converting Unicode->multi-byte
	bool m_datalost;

	UINT m_codepage;

};


//////////////////////////////////////////////////////////////////////////
// CTextFileWrite
//////////////////////////////////////////////////////////////////////////
class CTextFileWrite : public CTextFileBase
{

public:
	//Create textfile
	CTextFileWrite(const FILENAMECHAR* filename, TEXTENCODING encoding=ASCII)
	{
		m_hFile = ::CreateFile(	filename, 
			GENERIC_WRITE,
			0,
			NULL,
			CREATE_ALWAYS, 
			FILE_ATTRIBUTE_NORMAL,
			NULL);

		m_buffpos = -1;
		m_buffsize = 0;

		m_encoding = encoding;

		WriteBOM();
	}

	~CTextFileWrite()
	{
		Close();
	}

	void Write(const CStringA& text)
	{
		Write((const char*)text);
	}

	void Write(const CStringW& text)
	{
		Write((const wchar_t*)text);
	}

	//Write char*
	void Write(const char* text)
	{
		//ASCIItext file format?
		if(m_encoding == ASCII)
			WriteAsciiString(text);
		else
		{
			//Convert text to unicode
			CStringW utext;
			CharToWstring(text, utext);

			//OK, lets write unicode
			for(int i=0;
				i < utext.GetLength();
				i++)
			{
				WriteWchar(utext[i]);
			}

		}
	}

	//Write wcar_t*
	void Write(const wchar_t* utext)
	{
		//ASCII text file format?
		if(m_encoding == ASCII)
		{
			//Convert to string and write
			CStringA text;
			WcharToString(utext, text);
			WriteAsciiString((const char*)text);
		}
		else
		{
			while(*utext != 0)
			{
				WriteWchar(*utext);
				utext++;
			}
		}
	}
	
	//Write new line (two characters, 13 and 10)
	void WriteEndl()
	{
		if(m_encoding == ASCII)
		{
			WriteByte(0x0D);
			WriteByte(0x0A);
		}
		else 
		{
			WriteWchar(0x0D);
			WriteWchar(0x0A);
		}
	}

	//Close the file
	void Close()
	{
		if(IsOpen())
			Flush();

		CTextFileBase::Close();
	}


private:
	//Write and empty buffer
	void Flush()
	{
		DWORD nWritten;
		if (!::WriteFile(m_hFile, m_buf, m_buffpos+1, &nWritten, NULL))
		{
			//Something bad has happend! Close file
			CTextFileBase::Close();

			//Throw exception
			//throw CTextFileException(GetLastError());
			//_com_issue_error(AtlHresultFromLastError());
		}

		m_buffpos = -1;
	}

	void WriteWchar(const wchar_t ch)
	{
		//Write HO byte first?
		if(m_encoding == UNI16_BE)
		{
			//Write HO byte
			WriteByte((unsigned char) (ch >> 8) );
			//Write LO byte
			WriteByte((unsigned char) ch);
		}
		else if(m_encoding == UNI16_LE)
		{
			//Write LO byte
			WriteByte((unsigned char) ch);
			//Write HO byte
			WriteByte((unsigned char) (ch >> 8) );
		}
		else
		{
			//http://www.cl.cam.ac.uk/~mgk25/unicode.html#examples
			//http://www.ietf.org/rfc/rfc3629.txt

			//Just a single byte?
			if(ch <= 0x7F)
			{
				//U-00000000 - U-0000007F:  0xxxxxxx  
				WriteByte( (unsigned char) ch );
			}

			//Two bytes?
			else if(ch <= 0x7FF)
			{
				//U-00000080 - U-000007FF:  110xxxxx 10xxxxxx  
				WriteByte( (unsigned char) (0xC0 | (ch>>6)) );
				WriteByte( (unsigned char) (0x80 | (ch&0x3F)) );
			}

			//Three bytes?
			else if(ch <= 0xFFFF)
			{
				//U-00000800 - U-0000FFFF:  1110xxxx 10xxxxxx 10xxxxxx  
				WriteByte( (unsigned char) (0xE0 | (  ch>>12)		));
				WriteByte( (unsigned char) (0x80 | ( (ch>>6)&0x3F ) ));
				WriteByte( (unsigned char) (0x80 | ( ch&0x3F )		));
			}

			/* //UPS! I did some coding for UTF-32, may be useful in the future :-)
			//Four bytes?
			else if(ch <= 0x1FFFFF)
			{
			//U-00010000 - U-001FFFFF:  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx  
			WriteByte( (unsigned char) (0xF0 | (  ch>>18)		 ));
			WriteByte( (unsigned char) (0xA0 | ( (ch>>12)&0xA0 ) ));
			WriteByte( (unsigned char) (0xA0 | ( (ch>>6)&0xA0 ) ));
			WriteByte( (unsigned char) (0xA0 | ( ch&0xA0 )		));
			}

			//Five bytes bytes?
			else if(ch <= 0x3FFFFFF)
			{
			//U-00200000 - U-03FFFFFF:  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx  
			WriteByte( (unsigned char) (0xF8 | (  ch>>24)	 	 ));
			WriteByte( (unsigned char) (0xA0 | ( (ch>>18)&0xA0 ) ));
			WriteByte( (unsigned char) (0xA0 | ( (ch>>12)&0xA0 ) ));
			WriteByte( (unsigned char) (0xA0 | ( (ch>>6)&0xA0 ) ));
			WriteByte( (unsigned char) (0xA0 | ( ch&0xA0 )		));
			}

			//Five bytes bytes?
			else if(ch <= 0x7FFFFFFF)
			{
			//U-04000000 - U-7FFFFFFF:  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
			WriteByte( (unsigned char) (0xFC | (  ch>>30)		 ));
			WriteByte( (unsigned char) (0xA0 | ( (ch>>24)&0xA0 ) ));
			WriteByte( (unsigned char) (0xA0 | ( (ch>>18)&0xA0 ) ));
			WriteByte( (unsigned char) (0xA0 | ( (ch>>12)&0xA0 ) ));
			WriteByte( (unsigned char) (0xA0 | ( (ch>>6)&0xA0 ) ));
			WriteByte( (unsigned char) (0xA0 | ( ch&0xA0 )		));
			}*/

		}
	}

	//Write one byte
	void WriteByte(const unsigned char byte)
	{
		//Instead of writing, save data in buffer and write when buffer is full
		if(m_buffpos+1 >= BUFFSIZE)
			Flush();

		m_buffpos++;
		m_buf[m_buffpos] = byte;
	}


	//Write a c-string in ASCII. 
	//In versions before 1.02 this function wrote directly to file,
	//no buffer was used. But sense WriteEndl() used buffer the file was
	//written incorretly. Now buffer is used here too, this is the
	//fastest solution.
	void WriteAsciiString(const char* s)
	{	
		while(*s != '\0')
		{
			WriteByte(*s);
			s++;
		}
	}

	//Write byte order mark
	void WriteBOM()
	{
		//Write BOM
		if(IsOpen())
		{
			if(m_encoding == UNI16_BE || m_encoding == UNI16_LE)
			{
				//Write BOM
				WriteWchar( 0xFEFF );
			}
			else if(m_encoding == UTF_8)
			{
				//Write UTF-8 BOM.  0xEF 0xBB 0xBF
				WriteByte(0xEF);
				WriteByte(0xBB);
				WriteByte(0xBF);
			}
		}
	}

};


class CTextFileRead : public CTextFileBase
{

public:
	CTextFileRead(const FILENAMECHAR* filename)
	{

		m_hFile = ::CreateFile(	filename, 
			GENERIC_READ,
			FILE_SHARE_READ,
			NULL,
			OPEN_EXISTING, 
			FILE_ATTRIBUTE_NORMAL,
			NULL);

		m_firstLine = true;
		m_endoffile = (IsOpen()==0);

		//Force reading to buffer next time
		m_buffpos=-1;

		m_useExtraBuffer=false;

		ReadBOM();
	}


	//Returns false if end-of-file was reached
	//(line will not be changed). If returns true,
	//it means that last line ended with a line break.
	bool ReadLineA(CStringA& line)
	{
		//EOF?
		if(Eof())
			return false;

		if(m_encoding == ASCII)
		{
			return ReadCharLine(line);
		}

		CStringW wline;

		if(!ReadWcharLine(wline))
			return false;

		//Convert
		WcharToString((const wchar_t*)wline, line);

		return true;

	}

	bool ReadLineW(CStringW& line)
	{
		//EOF?
		if(Eof())
			return false;

		if(m_encoding == ASCII)
		{
			CStringA cline;

			if(!ReadCharLine(cline))
				return false;

			//Convert to CStringW
			CharToWstring((const char*)cline, line);

			return true;
		}

		return ReadWcharLine(line);

	}

	//Returns everything from current position.
	bool ReadA(CStringA& all, const CStringA newline)
	{
		if(!IsOpen())
			return false;

		int buffsize = GuessCharacterCount()+2;
		int buffpos = 0;

		//Create buffer
		char* buffer = new char[buffsize];

		//If not possible, don't use any buffer
		if(buffer == NULL) 
			buffsize = 0;

		CStringA temp;
		all = temp;
		//all.reserve(buffsize);
		bool firstLine=true;

		while(!Eof())
		{
			if(ReadLineA(temp))
			{
				//Add new line, if not first line
				if(!firstLine)
					temp.Insert(0, newline);
				else
					firstLine=false;

				//Add to buffer if possible
				if(buffpos + (int) temp.GetLength() < buffsize)
				{
					strcpy_s(buffer+buffpos, buffsize - buffpos, (const char*)temp);
					buffpos += (int) temp.GetLength();
				}
				else
				{
					//Copy to all string
					if(buffpos != 0)
					{
						all.Append(buffer, buffpos);
						buffpos = 0;
					}

					all += temp;
				}
			}
		};

		//Copy to all string
		if(buffpos != 0)
		{
			all.Append(buffer, buffpos);
		}

		if(buffer != NULL)
			delete [] buffer;

		return true;
	}

	bool ReadW(CStringW& all, const CStringW newline)
	{
		if(!IsOpen())
			return false;

		int buffsize = GuessCharacterCount()+2;
		int buffpos = 0;

		//Create buffer
		wchar_t* buffer = new wchar_t[buffsize];

		//If not possible, don't use any buffer
		if(buffer == NULL) 
			buffsize = 0;

		CStringW temp;
		all = temp;
		//all.reserve(buffsize);
		bool firstLine=true;

		while(!Eof())
		{
			if(ReadLineW(temp))
			{
				//Add new line, if not first line
				if(!firstLine)
					temp.Insert(0, newline);
				else
					firstLine=false;

				//Add to buffer if possible
				if(buffpos + (int) temp.GetLength() < buffsize)
				{
					wcscpy_s(buffer+buffpos, buffsize - buffpos, (const wchar_t*)temp);
					buffpos += (int) temp.GetLength();
				}
				else
				{
					//Copy to all string
					if(buffpos != 0)
					{
						all.Append(buffer, buffpos);
						buffpos = 0;
					}

					all += temp;
				}
			}
		};

		//Copy to all string
		if(buffpos != 0)
		{
			all.Append(buffer, buffpos);
		}

		if(buffer != NULL)
			delete [] buffer;

		return true;
	}


	bool ReadLine(CString& line)
	{
#ifndef _UNICODE
		CStringA temp;
		if(!ReadLineA(temp))
			return false;
#else
		CStringW temp;
		if(!ReadLineW(temp))
			return false;
#endif

		line = temp;
		return true;
	}

	bool Read(CString& all, const CString newline)
	{
#ifndef _UNICODE
		CStringA temp, n=newline;
		if(!ReadA(temp, n))
			return false;
#else
		CStringW temp, n=newline;
		if(!ReadW(temp, n))
			return false;
#endif


		all = temp;
		return true;
	}

	//End of file?
	bool Eof() const
	{
		return m_endoffile;
	}

    //Guess the number of characters in the file
private:
	//Guess the number of characters in the file
	int GuessCharacterCount()
	{
        int bytecount = (int) Size();

		//If ASCII, the number of characters is the byte count.
		//If UTF-8, it can't be more than bytecount, so use byte count
		if(m_encoding == ASCII || m_encoding == UTF_8)
			return bytecount;

		//Otherwise, every two byte in one character
		return bytecount/2;
	}


	//Returns false if end-of-file was reached
	//(line will not be changed). If returns true,
	//it means that last line ended with a line break.
	bool ReadWcharLine(CStringW& line)
	{
		//EOF?
		if(Eof())
			return false;

		wchar_t ch=0;

		//Ignore 0x0D and 0x0A
		//or just 0x0D
		//or just 0x0A
		//except when we read the first line
		ReadWchar(ch);

		if(!m_firstLine)
		{
			if(ch == 0x0D) //If next is 0x0A, ignore that too
			{
				ReadWchar(ch);

				if(ch == 0x0A)
					ReadWchar(ch);
			}
			else if(ch == 0x0A)
			{
				ReadWchar(ch);
			}
		}
		else
		{
			//Next time we reads we don't read the first line in file.
			//(then we should ignore \r\n)
			m_firstLine = false;
		}

		//Clear line
		line = L"";

		//It would be a lot easier if we didn't use a buffer, and added directly to
		//line, but that is quite slow.
		wchar_t buffer[BUFFSIZE];
		buffer[BUFFSIZE-1] = '\0';
		//Where to insert next character
		int bufpos = 0;

		//Read line
		while(ch != 0x0D && ch != 0x0A && !Eof())
		{
			//End of buffer?
			if(bufpos+1 >= BUFFSIZE)
			{
				//Add to line
				line.Append(buffer, bufpos);
				bufpos=0;
			}

			buffer[bufpos] = ch;
			bufpos++;

			ReadWchar(ch);
		};

		buffer[bufpos] = L'\0';
		line += buffer;

		//Save currents character in extra buffer
		m_useExtraBuffer=true;
		m_extraBuffer_wchar=ch;

		return true;
	}


	//Returns false if end-of-file was reached
	//(line will not be changed). If returns true,
	//it means that last line ended with a line break.
	bool ReadCharLine(CStringA& line)
	{
		//EOF?
		if(Eof())
			return false;

		unsigned char ch=0;

		//Ignore 0x0D and 0x0A
		//or just 0x0D
		//or just 0x0A
		//except when we read the first line
		ReadByte(ch);

		if(!m_firstLine)
		{		
			if(ch == 0x0D) //If next is 0x0A, ignore that too
			{
				ReadByte(ch);

				if(ch == 0x0A)
					ReadByte(ch);
			}
			else if(ch == 0x0A)
			{
				ReadByte(ch);
			}
		}
		else
		{
			//Next time we reads we don't read the first line in file.
			//(then we should ignore \r\n)
			m_firstLine = false;
		}

		//Clear line
		line = "";

		//It would be a lot easier if we didn't use a buffer, and added directly to
		//line, but that is quite slow.
		char buffer[BUFFSIZE];
		buffer[BUFFSIZE-1] = '\0';
		//Where to insert next character
		int bufpos = 0;

		//Read line
		while(ch != 0x0D && ch != 0x0A && !Eof())
		{
			//End of buffer?
			if(bufpos+1 >= BUFFSIZE)
			{
				//Add to line
				line.Append(buffer, bufpos);
				bufpos=0;
			}

			buffer[bufpos] = ch;
			bufpos++;

			ReadByte(ch);
		};

		buffer[bufpos] = L'\0';
		line += buffer;

		//Save currents character in extra buffer
		m_useExtraBuffer=true;
		m_extraBuffer_char=ch;

		return true;
	}

	//Reset the filepointer to start
	void ResetFilePointer()
	{
		m_useExtraBuffer=false;

		::SetFilePointer(m_hFile, 0, NULL, FILE_BEGIN);

		//Force reread buffer
		m_buffpos=-1;

		m_firstLine = true;
		m_endoffile = false;

	}

	//Read one wchar_t
	void ReadWchar(wchar_t& ch)
	{
		if(m_useExtraBuffer)
		{
			m_useExtraBuffer=false;
			ch = m_extraBuffer_wchar;
			return;
		}

		if(m_encoding == UTF_8)
		{	
			//This is quite tricky :-/
			//http://www.cl.cam.ac.uk/~mgk25/unicode.html#examples
			unsigned char byte;
			ReadByte(byte);

			int onesBeforeZero = 0;

			{	//Calc how many ones before the first zero...
				unsigned char temp = byte;

				while( (temp & 0x80)!=0 )
				{
					temp = (unsigned char) (temp << 1);
					onesBeforeZero++;
				}
			}

			if(onesBeforeZero==0)
			{
				ch = byte;
				return;
			}
			else if(onesBeforeZero == 2)
			{
				//U-00000080 - U-000007FF:  110xxxxx 10xxxxxx  
				unsigned char byteb;
				ReadByte(byteb);

				ch = (wchar_t)		 ( ((0x1F & byte) << 6)| 
					(0x3F & byteb)
					) ;

				return;
			}
			else if(onesBeforeZero == 3)
			{
				//U-00000800 - U-0000FFFF:  1110xxxx 10xxxxxx 10xxxxxx
				unsigned char byteb, bytec;
				ReadByte(byteb);
				ReadByte(bytec);

				ch = (wchar_t)  ( ((0x0F & byte) << 12) |
					((0x3F & byteb) << 6) | 
					(0x3F & bytec) );

				return;
			}

			//This should never happend! It it do, something is wrong with the file.
			ch = 0xFFFD;

		}
		else
		{

			unsigned char bytes[2];
			ReadByte(bytes[0]);
			ReadByte(bytes[1]); 

			if(m_encoding == UNI16_BE)
				ch = (wchar_t) ( ((wchar_t) bytes[0] << 8) | 
				(wchar_t) bytes[1] 
			) ;
			else
				ch = (wchar_t) ( ((wchar_t) bytes[1] << 8) | 
				(wchar_t) bytes[0] 
			);
		}
	}



	//Read one byte
	void ReadByte(unsigned char& ch)
	{
		//Use extrabuffer if needed
		if(m_useExtraBuffer)
		{
			m_useExtraBuffer=false;
			ch = m_extraBuffer_char;
			return;
		}

		//In Windows, do this...

		//If buffer used or not read
		if(m_buffpos==-1 || m_buffpos == BUFFSIZE-1)
		{
			DWORD dwRead;
			if (!::ReadFile(m_hFile, m_buf, BUFFSIZE, &dwRead, NULL))
			{
				//Couldn't read!
				Close();
				m_buffsize = 0;

				//Throw exception
				//throw CTextFileException(GetLastError());
				//_com_issue_error(AtlHresultFromLastError());

			}
			else
				m_buffsize = (int) dwRead;

			if(m_buffsize == 0)
			{
				m_endoffile=true;
				ch = 0;
				return;
			}

			m_buffpos=0;
		}
		else
		{
			m_buffpos++;

			if(m_buffpos >= m_buffsize)
			{
				m_endoffile=true;
				ch = 0;
				return;
			}
		}


		ch = m_buf[m_buffpos];
	}

	//Detect encoding
	void ReadBOM()
	{
		if( IsOpen() )
		{
			unsigned char bytes[2];

			//Read the first two bytes
			ReadByte(bytes[0]);
			ReadByte(bytes[1]);

			//Figure out what format the file is in
			if( bytes[0] == 0xFF && bytes[1] == 0xFE)
				m_encoding = UNI16_LE;
			else if( bytes[0] == 0xFE && bytes[1] == 0xFF)
				m_encoding = UNI16_BE;
			else if( bytes[0] == 0xEF && bytes[1] == 0xBB)
			{
				//This is probably UTF-8, check the third byte
				unsigned char temp;
				ReadByte(temp);
				if( temp == 0xBF)
					m_encoding = UTF_8;
				else
				{
					//Set text format.
					m_encoding = ASCII;
					ResetFilePointer();
				}
			}
			else
			{
				m_encoding = ASCII;

				//Set start pos
				ResetFilePointer();
			}
		}
	}


	//Use extra buffer. Sometimes we read one character to much, save it.
	bool m_useExtraBuffer;

	//Used to read see if the first line in file is to read 
	//(so we know how to handle \n\r)
	bool m_firstLine;

	//Extra buffer. It's ok to share the memory
	union
	{
		char m_extraBuffer_char;
		wchar_t m_extraBuffer_wchar;
	};

};


#endif //PEKSPRODUCTIONS_TEXTFILE
